package com.jz.netthings.netty.server;

import com.jz.netthings.netty.protocol.BasePacket;
import com.jz.netthings.netty.protocol.bean.HeartMsgPacket;
import com.jz.netthings.netty.protocol.bean.LoginRequestPacket;
import com.jz.netthings.netty.protocol.bean.LoginResponsePacket;
import com.jz.netthings.netty.support.Attributes;
import com.jz.netthings.netty.support.ServerHandlerSupport;
import com.jz.netthings.netty.support.Session;
import com.jz.netthings.utils.XmlHelper;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.ObjectInputStream;
import java.io.StringReader;
import java.util.HashMap;

@Service("nettyServerHandler")
//@Scope("prototype")
@ChannelHandler.Sharable
public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    ServerHandlerSupport nettyServerHandlerSupport;

    /**
     * 保存客户端的空闲次数
     */
    private HashMap<ChannelHandlerContext , Integer> countMap = new HashMap<>();


    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (IdleState.READER_IDLE.equals(event.state())) {  //如果读通道处于空闲状态，说明没有接收到心跳命令

                Integer idle_count = countMap.get(ctx);
                if (idle_count == null){
                    idle_count = 1;
                    countMap.put(ctx,idle_count);
                }else{
                    logger.info("已经很长时间没有收到客户端【" + ctx.channel().remoteAddress() + "】的信息了.......");
                    if (idle_count > 5) {
                        logger.info("关闭这个不活跃的channel...");
                        countMap.remove(ctx);
                        this.unBindSession(ctx);
                        ctx.close();
                    }else {
                        idle_count++;
                        countMap.put(ctx,idle_count);

                    }
                }


            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        logger.info("连接的客户端地址:" + ctx.channel().remoteAddress());
        super.channelActive(ctx);
    }


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        try {

            if (BasePacket.class.isAssignableFrom(msg.getClass())) {
                BasePacket packet = (BasePacket) msg;

//                logger.info("服务端接收到数据：" + ctx.channel().remoteAddress() + " ： " + packet);

                if (packet instanceof HeartMsgPacket) {
                    countMap.remove(ctx);
                    ctx.writeAndFlush(new HeartMsgPacket("服务端成功收到心跳信息"));
                }
                if (packet instanceof LoginRequestPacket) {
                    //是客户端的登录包
                    ((LoginRequestPacket) packet).setCtx(ctx);
                }

                BasePacket handlePacket = nettyServerHandlerSupport.handlePacket(packet);
                if (handlePacket != null) {
                    if (handlePacket instanceof LoginResponsePacket) {
                        //绑定channel和Packet
                        LoginResponsePacket responsePacket = (LoginResponsePacket) handlePacket;
                        if (responsePacket != null && responsePacket.isSuccess()) {
                            String uuid = responsePacket.getUuid();
                            boolean hasAttr = ctx.channel().hasAttr(Attributes.SESSION);

                            if (!hasAttr) {
                                ctx.channel().attr(Attributes.SESSION).set(new Session(uuid));
                            }

                        }
                    }
//                    logger.info("服务端返回给客户端的数据：" + handlePacket);
                    ctx.writeAndFlush(handlePacket);
                }
            }


        } finally {
            ReferenceCountUtil.release(msg);
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        //捕捉异常信息
        logger.error(cause.getMessage() + "【" + ctx.channel().remoteAddress() + "】");
        this.unBindSession(ctx);
        nettyServerHandlerSupport.freeMachineData(ctx);

        //出现异常时关闭channel
        ctx.close();
    }

    private void unBindSession(ChannelHandlerContext ctx) throws Exception {
        Attribute<Session> attribute = ctx.channel().attr(Attributes.SESSION);
        Session session = attribute.get();

        if (session != null) {
            nettyServerHandlerSupport.cleanRedisObj(session.getUuid());
            attribute.set(null);
        }
    }
}
